import os
from pathlib import Path
from typing import Dict, Any, Optional
from dataclasses import dataclass, field
import yaml
import json

@dataclass
class PathConfig:
    """路径配置类"""
    base_dir: Path
    models_dir: Path = field(init=False)
    datasets_dir: Path = field(init=False)
    logs_dir: Path = field(init=False)
    temp_dir: Path = field(init=False)
    pretrained_models_dir: Path = field(init=False)
    cloud_models_dir: Path = field(init=False)
    edge_models_dir: Path = field(init=False)
    
    def __post_init__(self):
        """初始化后设置派生路径"""
        self.models_dir = self.base_dir / "models"
        self.datasets_dir = self.base_dir / "datasets"
        self.logs_dir = self.base_dir / "logs"
        self.temp_dir = self.base_dir / "temp"
        self.pretrained_models_dir = self.models_dir / "pretrained"
        self.cloud_models_dir = self.models_dir / "cloud"
        self.edge_models_dir = self.models_dir / "edge"

@dataclass
class TrainingConfig:
    """训练配置类"""
    model_type: str = "yolov8n"
    task_type: str = "detection"
    epochs: int = 100
    batch_size: int = 16
    learning_rate: float = 0.001
    default_dataset: str = "10_cls_600"
    
    # 支持的模型类型
    supported_models: list = field(default_factory=lambda: [
        'yolov8n', 'yolov8s', 'yolov8m', 'yolov8l', 'yolov8x'
    ])
    
    # 支持的任务类型
    supported_tasks: list = field(default_factory=lambda: [
        'detection', 'classification', 'segmentation'
    ])

@dataclass
class APIConfig:
    """API配置类"""
    title: str = "边缘云端AI训练系统"
    description: str = "实现模型训练、数据传输、增量学习等功能的云端服务"
    version: str = "1.0.0"
    host: str = "0.0.0.0"
    port: int = 8000
    debug: bool = False
    
    # CORS配置
    cors_origins: list = field(default_factory=lambda: ["*"])
    cors_methods: list = field(default_factory=lambda: ["*"])
    cors_headers: list = field(default_factory=lambda: ["*"])
    
    # 请求限制
    max_request_size: int = 100 * 1024 * 1024  # 100MB
    request_timeout: int = 300  # 5分钟

@dataclass
class DatabaseConfig:
    """数据库配置类"""
    url: Optional[str] = None
    pool_size: int = 10
    max_overflow: int = 20
    pool_timeout: int = 30
    pool_recycle: int = 3600
    
    def __post_init__(self):
        """设置默认数据库URL"""
        if self.url is None:
            base_dir = Path(__file__).parent.parent
            self.url = f"sqlite:///{base_dir}/src/edge_cloud.db"

@dataclass
class LogConfig:
    """日志配置类"""
    level: str = "INFO"
    format: str = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
    max_file_size: int = 10 * 1024 * 1024  # 10MB
    backup_count: int = 5
    
    # 第三方库日志级别
    third_party_levels: Dict[str, str] = field(default_factory=lambda: {
        "urllib3": "WARNING",
        "requests": "WARNING", 
        "PIL": "WARNING",
        "sqlalchemy": "WARNING"
    })

class Config:
    """应用配置管理 - 单例模式"""
    
    _instance = None
    _initialized = False
    
    def __new__(cls):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
        return cls._instance
    
    def __init__(self):
        if self._initialized:
            return
        
        self._initialized = True
        
        # 基础路径配置
        self.base_dir = Path(__file__).parent.parent  # dec03-final根目录
        self.paths = PathConfig(self.base_dir)
        
        # 加载配置
        self._load_config()
        
        # 确保目录存在
        self.ensure_directories()
    
    def _load_config(self):
        """加载配置文件"""
        config_file = self.base_dir / "config.yaml"
        
        # 默认配置
        self.training = TrainingConfig()
        self.api = APIConfig()
        self.database = DatabaseConfig()
        self.log = LogConfig()
        self.raw_config = {}  # 存储原始配置数据
        
        # 如果配置文件存在，则加载并覆盖默认配置
        if config_file.exists():
            try:
                with open(config_file, 'r', encoding='utf-8') as f:
                    config_data = yaml.safe_load(f)
                
                if config_data:
                    self.raw_config = config_data  # 保存原始配置
                    self._update_config_from_dict(config_data)
                    
            except Exception as e:
                print(f"警告：加载配置文件失败: {e}，使用默认配置")
        
        # 环境变量覆盖
        self._load_from_env()
    
    def _update_config_from_dict(self, config_data: Dict[str, Any]):
        """从字典更新配置"""
        if 'training' in config_data:
            for key, value in config_data['training'].items():
                if hasattr(self.training, key):
                    setattr(self.training, key, value)
        
        if 'api' in config_data:
            for key, value in config_data['api'].items():
                if hasattr(self.api, key):
                    setattr(self.api, key, value)
        
        if 'database' in config_data:
            for key, value in config_data['database'].items():
                if hasattr(self.database, key):
                    setattr(self.database, key, value)
        
        if 'log' in config_data:
            for key, value in config_data['log'].items():
                if hasattr(self.log, key):
                    setattr(self.log, key, value)
        
        # 处理其他配置项（如 nodes, scheduling_strategies 等）
        for key, value in config_data.items():
            if key not in ['training', 'api', 'database', 'log']:
                setattr(self, key, value)
    
    def _load_from_env(self):
        """从环境变量加载配置"""
        # 数据库URL
        if os.getenv("DATABASE_URL"):
            self.database.url = os.getenv("DATABASE_URL")
        
        # 日志级别
        if os.getenv("LOG_LEVEL"):
            self.log.level = os.getenv("LOG_LEVEL")
        
        # API配置
        if os.getenv("API_HOST"):
            self.api.host = os.getenv("API_HOST")
        if os.getenv("API_PORT"):
            try:
                self.api.port = int(os.getenv("API_PORT"))
            except ValueError:
                pass
        if os.getenv("API_DEBUG"):
            self.api.debug = os.getenv("API_DEBUG").lower() in ['true', '1', 'yes']
    
    def ensure_directories(self):
        """确保必要的目录存在"""
        directories = [
            self.paths.models_dir,
            self.paths.datasets_dir,
            self.paths.logs_dir,
            self.paths.temp_dir,
            self.paths.pretrained_models_dir,
            self.paths.cloud_models_dir,
            self.paths.edge_models_dir
        ]
        
        for directory in directories:
            directory.mkdir(parents=True, exist_ok=True)
    
    def get_dataset_path(self, dataset_name: str) -> Path:
        """获取数据集路径"""
        if Path(dataset_name).is_absolute():
            return Path(dataset_name)
        else:
            return self.paths.datasets_dir / dataset_name
    
    def get_model_path(self, model_type: str) -> Path:
        """获取预训练模型路径"""
        return self.paths.pretrained_models_dir / f"{model_type}.pt"
    
    def get_cloud_model_path(self, model_id: str) -> Path:
        """获取云端模型路径"""
        return self.paths.cloud_models_dir / model_id
    
    def get_edge_model_path(self, model_id: str) -> Path:
        """获取边缘模型路径"""
        return self.paths.edge_models_dir / model_id
    
    def get_log_path(self, task_id: str) -> Path:
        """获取日志路径"""
        return self.paths.logs_dir / task_id / f"{task_id}.log"
    
    def get_temp_path(self, filename: str = "") -> Path:
        """获取临时文件路径"""
        if filename:
            return self.paths.temp_dir / filename
        else:
            return self.paths.temp_dir
    
    def create_config_file(self):
        """创建配置文件模板"""
        config_template = {
            'training': {
                'model_type': self.training.model_type,
                'task_type': self.training.task_type,
                'epochs': self.training.epochs,
                'batch_size': self.training.batch_size,
                'learning_rate': self.training.learning_rate,
                'default_dataset': self.training.default_dataset,
                'supported_models': self.training.supported_models,
                'supported_tasks': self.training.supported_tasks
            },
            'api': {
                'title': self.api.title,
                'description': self.api.description,
                'version': self.api.version,
                'host': self.api.host,
                'port': self.api.port,
                'debug': self.api.debug,
                'cors_origins': self.api.cors_origins,
                'max_request_size': self.api.max_request_size,
                'request_timeout': self.api.request_timeout
            },
            'database': {
                'pool_size': self.database.pool_size,
                'max_overflow': self.database.max_overflow,
                'pool_timeout': self.database.pool_timeout,
                'pool_recycle': self.database.pool_recycle
            },
            'log': {
                'level': self.log.level,
                'format': self.log.format,
                'max_file_size': self.log.max_file_size,
                'backup_count': self.log.backup_count,
                'third_party_levels': self.log.third_party_levels
            }
        }
        
        config_file = self.base_dir / "config.yaml"
        with open(config_file, 'w', encoding='utf-8') as f:
            yaml.dump(config_template, f, default_flow_style=False, allow_unicode=True)
        
        return config_file
    
    def get_config_dict(self) -> Dict[str, Any]:
        """获取完整配置字典"""
        return {
            'paths': {
                'base_dir': str(self.paths.base_dir),
                'models_dir': str(self.paths.models_dir),
                'datasets_dir': str(self.paths.datasets_dir),
                'logs_dir': str(self.paths.logs_dir),
                'temp_dir': str(self.paths.temp_dir),
                'pretrained_models_dir': str(self.paths.pretrained_models_dir),
                'cloud_models_dir': str(self.paths.cloud_models_dir),
                'edge_models_dir': str(self.paths.edge_models_dir)
            },
            'training': {
                'model_type': self.training.model_type,
                'task_type': self.training.task_type,
                'epochs': self.training.epochs,
                'batch_size': self.training.batch_size,
                'learning_rate': self.training.learning_rate,
                'default_dataset': self.training.default_dataset,
                'supported_models': self.training.supported_models,
                'supported_tasks': self.training.supported_tasks
            },
            'api': {
                'title': self.api.title,
                'description': self.api.description,
                'version': self.api.version,
                'host': self.api.host,
                'port': self.api.port,
                'debug': self.api.debug
            },
            'database': {
                'url': self.database.url,
                'pool_size': self.database.pool_size
            },
            'log': {
                'level': self.log.level,
                'format': self.log.format
            }
        }

# 全局配置实例
config = Config() 